// TODO: 优化边界判断
use std::ops::Sub;

pub fn time_info(time: &str) -> String {
    let vec: Vec<&str> = time.split('-').collect();

    let year = vec[0].parse::<isize>().unwrap();
    let month = vec[1].parse::<usize>().unwrap();
    let day = vec[2].parse::<usize>().unwrap();

    let week_num = get_curr_week_since_this_year(year, month, day);
    let remain_day_to_new_year = how_many_days_between(
        (year, month, day),
        (year + 1, 1, 1)
    );

    let curr_lunar_date = lunar_cal::get_lunar_new_year_date(year);
    let remain_day_to_next_lunar_new_year = how_many_days_between(
        (year, month, day),
        lunar_cal::get_lunar_new_year_date(year + 1),
    );

    let remain_of_next_lunar = if curr_lunar_date < (year, month, day) {
       remain_day_to_next_lunar_new_year
    } else {
        let remain_day_to_curr_lunar_new_year = how_many_days_between(
            (year, month, day),
            curr_lunar_date
        );
        std::cmp::min(remain_day_to_curr_lunar_new_year, remain_day_to_next_lunar_new_year)
    };

    format!("{},{},{}",
            week_num,
            remain_day_to_new_year,
            remain_of_next_lunar
    )
}

/// 判断是否为闰年
/// 参照公历规范实现： 闰年是指能被4整除的年份，但如果能被100整除而不能被400整除的年份就不是闰年
pub fn is_leap_year(year: isize) -> bool {
    (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
}

/// 生成距离公元元年的天数
pub fn days_until_year(mut year: isize) -> isize {
    // ISO 8601: 其中0000意爲公元前1年
    if year == 0 { year = -1 } 
    if year > 0 { 
        // BC
        (year - 1) * 365 + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400
    } else { 
        // AC
        year * 365 + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400
    }
}

/// 获取本月的总天数
pub fn how_many_days_of_this_month(year: isize, month: usize) -> usize {
    if month == 0 || month > 12 { panic!("Incorrect Format") }
    match month {
        4 | 6 | 9 | 11 => 30,
        2 if is_leap_year(year) => 29,
        2 if ! is_leap_year(year) => 28,
        _ => 31,
    }
}

/// 获取自某年一月一日至某月第一天的总天数
pub fn days_until_months_since_years(year: isize, month: usize) -> usize {
    let mut days = 0;
    for m in 1..month {
        days += how_many_days_of_this_month(year, m);
    }
    days
}

/// 计算两个不同 Date 中的差距
pub fn how_many_days_between((year, month, day): (isize, usize, usize), (y, m, d): (isize, usize, usize)) -> usize {
    if month > 12 || day > how_many_days_of_this_month(year, month) ||
        m > 12 || d > how_many_days_of_this_month(y, m) {
        panic!("Incorrect Data: month or day overflow");
    }
    let date1 = days_until_year(year) + days_until_months_since_years(year, month) as isize + day as isize;
    let date2 = days_until_year(y) + days_until_months_since_years(y, m) as isize + d as isize;
    (date2 - date1 - 1).abs() as usize
}

/// 基于蔡勒公式(Zellers Kongruenz)计算(Y, M, D)是周几
/// https://zh.wikipedia.org/wiki/%E8%94%A1%E5%8B%92%E5%85%AC%E5%BC%8F
/// w = \left ( y + \left[\frac{y}{4}\right] + \left[\frac{c}{4}\right] - 2c + \left[\frac{26(m+1)}{10}\right] +d -1 \right ) \bmod 7
pub fn zellers_kongruenz(mut year: isize, mut month: usize, day: usize) -> usize {
    if year <= 0 { panic!("Incorrect Data: zellers_kongruenz only support BC") }
    if month > 12 || day > how_many_days_of_this_month(year, month) {
        panic!("Incorrect Data: month or day overflow");
    }
    
    // 菜勒要求1-3月被诗作为前一年的13-14月
    if month < 3 {
        month += 12;
        year -= 1;
    };

    let (c, y) = (year as usize / 100, year as usize % 100);
    let week_days = (y + y / 4 + c / 4+ 26 * (month + 1) / 10 + day).sub(2 * c + 1);

    (week_days as usize % 7 + 7) % 7
}

/// 获取 (year, month, day) 对应的周数
///
/// 周数计算方式参照 ISO 8601:
///     一年的第一周是1月的第一个周四所在的周
///     如果1月1日是星期五、六或日，这天属于上一年的最后一周。
pub fn get_curr_week_since_this_year(year: isize, month: usize, day: usize) -> usize {
    if month > 12 || day > how_many_days_of_this_month(year, month) {
        panic!("Incorrect Data: month or day overflow");
    }
    let jan1_weekday: isize = zellers_kongruenz(year, 1, 1) as isize;
    let total_day: isize = (days_until_months_since_years(year, month) + day) as isize;
    let next_jan1_offset: isize = zellers_kongruenz(year + 1, 1, 1) as isize;
    // if offset = 0..4 => in next year
    // else is this year
    if total_day >= 365 && next_jan1_offset <= 4 { // belong to next year
       return 1
    }

    let jan1_offset = match jan1_weekday {
        0 => -1,
        1..=4 => jan1_weekday,
        5 => -3,
        _ => -2,
    };

    let temp = jan1_offset + total_day - 1;
    if temp % 7 != 0 {
        (temp / 7 + 1) as usize
    } else {
        (temp / 7) as usize
    }
}

pub mod lunar_cal {
    /// DATA FROM https://blog.csdn.net/qq_41146650/article/details/102876334
    /// 使用比特位记录每年的情况
    /// 0~4 共5bit 春节日份
    /// 5~6 共2bit 春节月份
    /// 7~19 共13bit 13个月的大小月情况(如果无闰月，最后位无效)，大月为1（30天）,小月为0（29天）
    /// 20~23 共4bit 记录闰月的月份，如果没有闰月为0
    const LUNAR_NEW_YEAR: [u32; 199] = [
        0x04AE53, 0x0A5748, 0x5526BD, 0x0D2650, 0x0D9544, 0x46AAB9, 0x056A4D, 0x09AD42, 0x24AEB6, 0x04AE4A, /*1901-1910*/
        0x6A4DBE, 0x0A4D52, 0x0D2546, 0x5D52BA, 0x0B544E, 0x0D6A43, 0x296D37, 0x095B4B, 0x749BC1, 0x049754, /*1911-1920*/
        0x0A4B48, 0x5B25BC, 0x06A550, 0x06D445, 0x4ADAB8, 0x02B64D, 0x095742, 0x2497B7, 0x04974A, 0x664B3E, /*1921-1930*/
        0x0D4A51, 0x0EA546, 0x56D4BA, 0x05AD4E, 0x02B644, 0x393738, 0x092E4B, 0x7C96BF, 0x0C9553, 0x0D4A48, /*1931-1940*/
        0x6DA53B, 0x0B554F, 0x056A45, 0x4AADB9, 0x025D4D, 0x092D42, 0x2C95B6, 0x0A954A, 0x7B4ABD, 0x06CA51, /*1941-1950*/
        0x0B5546, 0x555ABB, 0x04DA4E, 0x0A5B43, 0x352BB8, 0x052B4C, 0x8A953F, 0x0E9552, 0x06AA48, 0x6AD53C, /*1951-1960*/
        0x0AB54F, 0x04B645, 0x4A5739, 0x0A574D, 0x052642, 0x3E9335, 0x0D9549, 0x75AABE, 0x056A51, 0x096D46, /*1961-1970*/
        0x54AEBB, 0x04AD4F, 0x0A4D43, 0x4D26B7, 0x0D254B, 0x8D52BF, 0x0B5452, 0x0B6A47, 0x696D3C, 0x095B50, /*1971-1980*/
        0x049B45, 0x4A4BB9, 0x0A4B4D, 0xAB25C2, 0x06A554, 0x06D449, 0x6ADA3D, 0x0AB651, 0x093746, 0x5497BB, /*1981-1990*/
        0x04974F, 0x064B44, 0x36A537, 0x0EA54A, 0x86B2BF, 0x05AC53, 0x0AB647, 0x5936BC, 0x092E50, 0x0C9645, /*1991-2000*/
        0x4D4AB8, 0x0D4A4C, 0x0DA541, 0x25AAB6, 0x056A49, 0x7AADBD, 0x025D52, 0x092D47, 0x5C95BA, 0x0A954E, /*2001-2010*/
        0x0B4A43, 0x4B5537, 0x0AD54A, 0x955ABF, 0x04BA53, 0x0A5B48, 0x652BBC, 0x052B50, 0x0A9345, 0x474AB9, /*2011-2020*/
        0x06AA4C, 0x0AD541, 0x24DAB6, 0x04B64A, 0x69573D, 0x0A4E51, 0x0D2646, 0x5E933A, 0x0D534D, 0x05AA43, /*2021-2030*/
        0x36B537, 0x096D4B, 0xB4AEBF, 0x04AD53, 0x0A4D48, 0x6D25BC, 0x0D254F, 0x0D5244, 0x5DAA38, 0x0B5A4C, /*2031-2040*/
        0x056D41, 0x24ADB6, 0x049B4A, 0x7A4BBE, 0x0A4B51, 0x0AA546, 0x5B52BA, 0x06D24E, 0x0ADA42, 0x355B37, /*2041-2050*/
        0x09374B, 0x8497C1, 0x049753, 0x064B48, 0x66A53C, 0x0EA54F, 0x06B244, 0x4AB638, 0x0AAE4C, 0x092E42, /*2051-2060*/
        0x3C9735, 0x0C9649, 0x7D4ABD, 0x0D4A51, 0x0DA545, 0x55AABA, 0x056A4E, 0x0A6D43, 0x452EB7, 0x052D4B, /*2061-2070*/
        0x8A95BF, 0x0A9553, 0x0B4A47, 0x6B553B, 0x0AD54F, 0x055A45, 0x4A5D38, 0x0A5B4C, 0x052B42, 0x3A93B6, /*2071-2080*/
        0x069349, 0x7729BD, 0x06AA51, 0x0AD546, 0x54DABA, 0x04B64E, 0x0A5743, 0x452738, 0x0D264A, 0x8E933E, /*2081-2090*/
        0x0D5252, 0x0DAA47, 0x66B53B, 0x056D4F, 0x04AE45, 0x4A4EB9, 0x0A4D4C, 0x0D1541, 0x2D92B5            /*2091-2099*/
    ];
    const START_YEAR: isize = 1901;

    /// 获取公历某一年对应的农历大年初一的时间
    pub fn get_lunar_new_year_date(year: isize) -> (isize, usize, usize) {
        if year < 1901 || year > 2099 { panic!("get_lunar_new_year_date only support Year in 1901-2099")}

        let abs_year = (year - START_YEAR) as usize;
        (
            year,
            ((LUNAR_NEW_YEAR[abs_year] >> 5) & 0x03) as usize,
            (LUNAR_NEW_YEAR[abs_year] & 0x1f) as usize
        )
    }
}
